<template>
  <a-card :bordered="false" :bodyStyle="{ padding: 0 }">
    <div style="display: flex;">
      <!--        左侧 规则树 start-->

      <a-col :xs="12" :md="6" :lg="6">
        <resizable-grid>
          <a-spin :spinning="treeLoading">
            <div class="custom-col-left-actions">
              <span style="float: left;margin-left:8px;margin-top:7px; ">{{
                $t('technology.serial.serialClass')
              }}</span>
              <a-button
                v-action:add
                style="float: right;margin-top: 2px;"
                type="link"
                @click="handleModalOpen(1, false)"
                >{{ $t('technology.serial.newClass') }}</a-button
              >
            </div>
            <a-input-search
              :placeholder="$t('common.query')"
              v-model="ruleSearchText"
              style="padding:8px;"
              @search="onRuleSearch"
              allowClear
            />
            <a-tree
              class="tree--custom has-menu"
              :replaceFields="{ title: 'ruleName', key: 'id' }"
              :treeData="ruleTree"
              :selectedKeys="selectedKeys"
              :expandedKeys.sync="expandedKeys"
              @select="onSelect"
            >
              <template slot="title" slot-scope="item">
                <div class="tree--custom-node">
                  <div class="tree--custom-node-text" :title="item.ruleName">
                    <a-icon type="folder" v-if="item.level === 1" />
                    {{ item.ruleName }}
                  </div>
                  <div class="tree--custom-node-menu" v-action:add|edit|delete>
                    <a-dropdown :trigger="['hover']">
                      <a class="ant-dropdown-link" href="javascript:;"><a-icon type="more" /> </a>
                      <a-menu slot="overlay" @click="({ key }) => onClickTypeDropdown(key, item)">
                        <a-menu-item v-action:add key="newRule" v-if="item.level === 1">
                          <a-icon type="plus" />{{ $t('technology.serial.newRule') }}</a-menu-item
                        >
                        <a-menu-item v-action:add key="newInstance" v-if="item.level === 2">
                          <a-icon type="plus" />{{ $t('technology.serial.newInstance') }}</a-menu-item
                        >
                        <a-menu-item v-action:edit key="edit"
                          ><a-icon type="edit" />{{ $t('common.edit') }}</a-menu-item
                        >
                        <a-menu-item v-action:delete key="delete" :disabled="item.children.length === -1">
                          <a-icon type="delete" />{{ $t('common.delete') }}
                        </a-menu-item>
                      </a-menu>
                    </a-dropdown>
                  </div>
                </div>
              </template>
            </a-tree>
          </a-spin>
        </resizable-grid>
      </a-col>

      <!--        左侧 规则树 end-->

      <a-col
        :xs="12"
        :md="18"
        :lg="18"
        style="padding: 20px; border-left: 1px solid #e8e8e8;"
        :style="{ minHeight: `${layoutContentHeight - pageHeaderHeight}px` }"
      >
        <a-spin :spinning="rightLoading">
          <template v-if="!selectedKeys.length || !ruleObj">
            <a-empty :image="simpleImage" :description="$t('technology.serial.initSerialRuleTip')" />
          </template>
          <rule-config-form
            v-else
            ref="ruleConfigForm"
            :rule="ruleObj"
            :sectionList="sectionList"
            :initSectionList="initSectionList"
            @reset="id => getSerialSectionList(id)"
          ></rule-config-form>
        </a-spin>
      </a-col>
    </div>

    <!--      序列号新建分类规则实例模态框 start-->
    <a-modal
      :title="modalTitle"
      :visible="visible"
      :width="500"
      @ok="handleModalOk"
      @cancel="handleModalCancel"
      :afterClose="afterClose"
    >
      <a-form-model
        ref="modalForm"
        :model="modalForm"
        :label-col="{ lg: { span: 4 }, sm: { span: 4 } }"
        :wrapper-col="{ lg: { span: 18 }, sm: { span: 18 } }"
      >
        <a-form-model-item
          :label="$t('common.name')"
          prop="name"
          :rules="[
            {
              required: true,
              message: $t('common.emptyErr', { name: $t('common.name') }),
              trigger: 'change',
              whitespace: true
            },
            { validator: validator.ruleNameValidator }
          ]"
        >
          <s-input v-model.trim="modalForm.name" :limit="64"></s-input>
        </a-form-model-item>
        <a-form-model-item
          v-if="modalType !== 1"
          :label="$t('technology.serial.code')"
          prop="code"
          :rules="[
            {
              required: modalType !== 1,
              message: $t('common.emptyErr', { name: $t('technology.serial.code') }),
              trigger: 'change',
              whitespace: true
            },
            { validator: validator.ruleCodeValidator }
          ]"
        >
          <s-input v-model.trim="modalForm.code" :limit="64"></s-input>
        </a-form-model-item>
      </a-form-model>
    </a-modal>
    <!--      序列号新建分类规则实例模态框 end-->
  </a-card>
</template>

<script>
import { breadFirstTree, getTreeNodeById } from '@/utils/util';
import { asyncValidateMixin, layoutMixin } from '@/utils/mixin';
import { ResizableGrid, SInput } from '@/components';
import {
  getSerialTree,
  getSerialRule,
  addSerialRule,
  updateSerialRule,
  delSerialRule,
  validateSerialRule,
  getSerialSectionList
} from '@/api/technology/serial/serial';
import { Empty } from 'ant-design-vue';
import RuleConfigForm from './modules/RuleConfigForm.vue';
import cloneDeep from 'lodash.clonedeep';

const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
export default {
  name: 'SerialNumberManage',
  mixins: [layoutMixin, asyncValidateMixin],

  components: {
    ResizableGrid,
    SInput,
    RuleConfigForm
  },

  data() {
    return {
      simpleImage,
      ruleSearchText: '',
      defaultSelectId: null,
      firstNodeId: null,
      ruleTree: [],
      ruleTreeB: [],
      selectedKeys: [],
      selectedNode: null,
      isRuleSelected: true,
      expandedKeys: [],

      modalType: 1, // 类型:1分类 2规则 3实例 也是树节点的level字段
      isModalEdit: false,
      visible: false,
      treeLoading: false,
      rightLoading: false,
      modalForm: {
        id: '',
        name: '',
        code: '',
        parentId: ''
      },

      ruleObj: null,
      sectionList: [],
      initSectionList: []
    };
  },
  created() {
    const { id } = this.$route.query;
    this.defaultSelectId = id ? parseInt(id) : null;
    this.init();
    this.$_asyncValidateMixin_init([
      {
        fieldName: 'ruleName',
        caller: validateSerialRule,
        extraParams: () => ({
          id: this.modalForm.id,
          level: this.modalType,
          parentId: this.modalForm.parentId
        })
      },
      {
        fieldName: 'ruleCode',
        caller: validateSerialRule,
        extraParams: () => ({
          id: this.modalForm.id,
          level: this.modalType,
          parentId: this.modalForm.parentId
        })
      }
    ]);
  },

  methods: {
    init() {
      this.treeLoading = true;
      getSerialTree()
        .then(res => {
          const treeData = res.data;
          breadFirstTree(
            treeData,
            node => {
              node.scopedSlots = {
                title: 'title'
              };
              node.title = node.ruleName;
              node.key = node.id;
              node.value = node.id;
              if (!this.defaultSelectId && node.level === 2) {
                this.defaultSelectId = node.id;
              }
              return true;
            },
            'children'
          );
          this.ruleTree = treeData;
          this.ruleTreeB = treeData;
          if (this.defaultSelectId) {
            this.onSelect([this.defaultSelectId]);
            this.expandedKeys = this.getDefaultExpandedKeys(this.defaultSelectId);
          }
        })
        .finally(() => {
          this.treeLoading = false;
        });
    },

    // 选中分类节点
    onSelect(selectedKeys, data) {
      // 反选当前节点不予理会
      if (selectedKeys.length === 0) {
        return;
      }
      const node = data ? data.node.dataRef : getTreeNodeById(this.ruleTree, selectedKeys[0], 'children');
      // 点击规则获取区域
      if (node.level === 2) {
        this.getSerialSectionList(selectedKeys[0]);
      }
      this.selectedKeys = selectedKeys;
      this.selectedNode = node;
      this.$router.push({
        query: {
          id: selectedKeys[0]
        }
      });
      this.queryRule(selectedKeys[0]);
    },

    /**
     * 默认展开到选中的节点。如果没有选中的节点，则展开第一个节点
     */
    getDefaultExpandedKeys(selectedId) {
      const expandedKeys = [];
      if (selectedId) {
        breadFirstTree(
          this.ruleTree,
          jn => {
            if (jn.parentId === selectedId) {
              expandedKeys.push(jn.parentId);
            }
            if (jn.id === selectedId) {
              expandedKeys.push(jn.parentId);
            }
            return true;
          },
          'children'
        );
      } else {
        expandedKeys.push(this.defaultSelectId);
      }
      return expandedKeys;
    },

    filterByRule(list, key, ckey, txt) {
      const ret = [];
      list.forEach(d => {
        let obj = {};
        if (d[key].includes(txt)) {
          obj = d;
        }
        if (d[ckey].length) {
          obj[ckey] = this.filterByRule(d[ckey], key, ckey, txt);
        }
        ret.push(obj);
      });
      return ret;
    },

    treeToTable(tree, ckey) {
      const list = [];
      this.handleTreeList(tree, ckey, list);
      return list;
    },

    handleTreeList(treeList, ckey, list) {
      if (!treeList || !treeList.length) {
        return;
      }
      for (let i = 0; i < treeList.length; i++) {
        const currentRow = treeList[i];
        list.push(currentRow);
        this.handleTreeList(currentRow[ckey], ckey, list);
      }
    },

    tableToTree(data, ckey, Id, Pid) {
      const result = [];
      if (!Array.isArray(data)) {
        return result;
      }
      data.forEach(item => {
        delete item[ckey];
      });
      const map = {};
      data.forEach(item => {
        map[item[Id]] = item;
      });
      data.forEach(item => {
        const parent = map[item[Pid]];
        if (parent) {
          (parent[ckey] || (parent[ckey] = [])).push(item);
        } else {
          result.push(item);
        }
      });
      return result;
    },

    // nodes就是树形的最原始数据，query就是关键字，最后会返回满足条件的节点数组
    filter(nodes, query, key, ckey) {
      // 条件就是节点的title过滤关键字
      const predicate = function(node) {
        if (node[key].indexOf(query) > -1) {
          return true;
        }
        return false;
      };
      if (!(nodes && nodes.length)) {
        return [];
      }
      const newChildren = [];
      for (const node of nodes) {
        // 以下两个条件任何一个成立，当前节点都应该加入到新子节点集中
        // 1. 子孙节点中存在符合条件的，即 subs 数组中有值
        // 2. 自己本身符合条件
        const subs = this.filter(node[ckey], query, key, ckey);
        if (predicate(node)) {
          newChildren.push(node);
        } else if (subs && subs.length) {
          node[ckey] = subs;
          newChildren.push(node);
        }

        // 以下只需要考虑自身的节点满足条件即可,不用带上父节点
        // if (predicate(node)) {
        //   newChildren.push(node)
        //   node[ckey] = this.filter(node[ckey], query, key, ckey)
        // } else {
        //   newChildren.push(...this.filter(node[ckey], query, key, ckey))
        // }
      }
      return newChildren.length ? newChildren : [];
    },
    // 序列号树的查找
    onRuleSearch() {
      if (this.ruleSearchText) {
        this.ruleTree = this.filter(this.ruleTreeB, this.ruleSearchText, 'ruleName', 'children');
        if (this.ruleTree.length > 0) {
          this.onSelect([this.ruleTree[0].id]);
        }
      } else {
        this.init();
      }
    },

    onClickTypeDropdown(key, item) {
      switch (key) {
        case 'newRule':
          this.handleModalOpen(2, false, item.id);
          break;
        case 'newInstance':
          this.handleModalOpen(3, false, item.id);
          break;
        case 'edit':
          this.modalForm.name = item.ruleName;
          this.modalForm.code = item.ruleCode;
          this.handleModalOpen(item.level, true, null, item.id);
          break;
        case 'delete': {
          if (item.children.length > 0) {
            if (item.parentId) {
              this.$notification.warning({
                message: this.$t('common.warning'),
                description: this.$t('technology.serial.deleteTipForRule')
              });
            } else {
              this.$notification.warning({
                message: this.$t('common.warning'),
                description: this.$t('technology.serial.deleteTipForClass')
              });
            }
            return;
          }
          let name = this.$t('technology.serial.rule');
          if (item.level === 1) {
            name = this.$t('technology.serial.class');
          } else if (item.level === 3) {
            name = this.$t('technology.serial.instance');
          }

          this.$confirm({
            title: this.$t('common.warning'),
            content: this.$t('common.delWarning', {
              name: name.toLowerCase()
            }),
            onOk: () => {
              delSerialRule({
                id: item.id
              }).then(res => {
                if (res.code === 'sso.ok') {
                  this.$message.success(this.$t(res.message));
                  if (this.selectedKeys.includes(item.id)) {
                    this.defaultSelectId = null;
                    this.selectedKeys = [];
                    this.selectedNode = null;
                    this.ruleObj = null;
                    this.$router.push({
                      query: {}
                    });
                  }
                  this.init();
                }
              });
            }
          });
          break;
        }
        default:
      }
    },

    handleModalOk() {
      const { isModalEdit, modalType, modalForm } = this;
      this.$refs.modalForm.validate().then(() => {
        if (isModalEdit) {
          updateSerialRule({
            level: modalType,
            ruleName: modalForm.name,
            ruleCode: modalType === 1 ? undefined : modalForm.code,
            id: modalForm.id
          }).then(() => {
            this.init();
            this.handleModalCancel();
          });
        } else {
          addSerialRule({
            level: modalType,
            ruleName: modalForm.name,
            ruleCode: modalType === 1 ? undefined : modalForm.code,
            parentId: modalType === 1 ? undefined : modalForm.parentId
          }).then(() => {
            this.init();
            this.handleModalCancel();
          });
        }
      });
    },

    handleModalCancel() {
      this.visible = false;
    },

    afterClose() {
      this.modalType = 1;
      this.isModalEdit = false;
      this.$refs.modalForm.resetFields();
      this.modalForm = {
        id: '',
        name: '',
        code: '',
        parentId: ''
      };
    },

    handleModalOpen(type, isEdit, parentId, id) {
      this.visible = true;
      this.modalType = type;
      this.isModalEdit = isEdit;
      this.modalForm.parentId = parentId;
      this.modalForm.id = id;
    },
    getSerialSectionList(id) {
      const param = {
        serialNumId: id
      };
      this.rightLoading = true;
      getSerialSectionList(param)
        .then(res => {
          this.sectionList = res.data || [];
          this.initSectionList = cloneDeep(res.data) || [];
          this.$nextTick(() => {
            if (!this.$refs.ruleConfigForm) return;
            this.$refs.ruleConfigForm.sectionList = res.data || [];
            this.$refs.ruleConfigForm.initSectionList = this.initSectionList || [];
          });
        })
        .finally(() => {
          this.rightLoading = false;
        });
    },

    queryRule(id) {
      getSerialRule({
        id
      })
        .then(res => {
          this.ruleObj = res.data;
        })
        .catch(() => {});
    }
  },
  computed: {
    modalTitle() {
      const { isModalEdit, modalType } = this;
      if (isModalEdit) {
        if (modalType === 1) {
          return this.$t('common.edit') + this.$t('technology.serial.class');
        }
        if (modalType === 2) {
          return this.$t('common.edit') + this.$t('technology.serial.rule');
        }
        return this.$t('common.edit') + this.$t('technology.serial.instance');
      }
      if (modalType === 1) {
        return this.$t('technology.serial.newClass');
      }
      if (modalType === 2) {
        return this.$t('technology.serial.newRule');
      }
      return this.$t('technology.serial.newInstance');
    },
    modalFieldName() {
      const { modalType } = this;
      if (modalType === 1) {
        return this.$t('technology.serial.newClass') + this.$t('common.name');
      }
      if (modalType === 2) {
        return this.$t('technology.serial.newRule') + this.$t('common.name');
      }
      return this.$t('technology.serial.newInstance') + this.$t('common.name');
    }
  },
  watch: {
    ruleSearchText() {
      this.onRuleSearch();
    }
  }
};
</script>

<style lang="less" scoped>
.custom-col-left-actions {
  text-align: center;
}
</style>
